﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

    public class ByteArrayEx
    {
        private const int constSize = 4096;
        private int _position = 0;
        private int _length = 0;
        private Boolean Is_Little_Endian = BitConverter.IsLittleEndian;
        private byte[] ByteArray;

        public ByteArrayEx(int size)
        {
            ByteArray = new byte[size];
        }

        public ByteArrayEx(byte[] arr)
        {
            ByteArray = new byte[arr.Length];
            Array.Copy(arr, ByteArray, arr.Length);
            _length = arr.Length;
            //ByteArray = arr;
        }

        public ByteArrayEx()
		{
            ByteArray = new byte[constSize];
		}

        public byte[] byteArray
        {
            get 
            {
                Array.Resize(ref ByteArray, _length);
                return ByteArray; 
            }
            set { ByteArray = value; }
        }

        public int length
        {
            get { return _length; }
            set { _length = value; }
        }

        public int bytesAvailable
        {
            get
            { return (_length - _position); }
        }

        public int position
        {
            get { return _position; }
            set { _position = value; }
        }

        /// <summary>
        /// VISTYPE_BYTE 		= 0;		// 一字节
        /// VISTYPE_WORD = 1;		// 二字节
        /// VISTYPE_DWORD = 2;		// 四字节
        /// VISTYPE_FLOAT = 3;		// 浮点四字节
        /// VISTYPE_LONGSTR = 4;	    // 字符串,第一、二个字节为长度,小于
        /// VISTYPE_WIDESTR = 5;	    // UNICODE宽字符串
        /// VISTYPE_OBJECT = 6;		// 对象号
        /// </summary>
        public object GetDataByType(int type)
		{
            object s = null;
            switch (type)
            {
                case (int)DataType.Value_Type.VARTYPE_BOOL:
                    {
                        s = readByte();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_INT32:
                    {
                        s = readInt();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_FLOAT: // float
                    {
                        s =readFloat();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_STRING:
                    {
                        s = readMultiByteEx();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_WIDESTR:
                    {
                        s = readWString();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_OBJECT:
                    {
                        s = readObject();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_DOUBLE:
                    {
                        s = readDouble();
                        break;
                    }

                case (int)DataType.Value_Type.VARTYPE_INT8:
                    {
                        s = readInt8();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_INT16:
                    {
                        s = readSignedShort();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_INT64:
                    {
                        s = readInt64();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_UINT64:
                    {
                        s = readUInt64();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_UINT8:
                    {
                        s = readByte();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_UINT16:
                    {
                        s = readUnsignedShort();
                        break;
                    }
                case (int)DataType.Value_Type.VARTYPE_UINT32:
                    {
                        s = readUInt32();
                        break;
                    }
                default:
                    {
                        Debug.Log("no fit type!");
                        //System.Diagnostics.Debug.Fail("No conversion provided for this type : " + typeCode.ToString());
                        break;
                    }
            }
            return s;
        }

        /// <summary>
        ///DATATYPE_INT		 = 2;	// 整数(4 bytes)	
        ///DATATYPE_FLOAT = 3;	// 浮点数(4 bytes)
        ///DATATYPE_STRING = 4;	// 字符串长度(2 bytes)+字符串(以结束)
        ///DATATYPE_WIDESTR = 5;	// 字符串长度(2 bytes)+宽字符串(以结束)
        ///DATATYPE_OBJECT = 6;	// 对象标识符nIdent(4 bytes)+nSerial(4 bytes)
        /// </summary>
        public void WriteData(object obj)
        {
            TypeCode typeCode;
            // 列举结构体的每个成员，并Reverse
            typeCode = Type.GetTypeCode(obj.GetType());  // get type
            if (obj is int || obj is uint)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_INT32);
                writeInt((int)obj);
            }
            else if (obj is Single)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_FLOAT);
                writeFloat((Single)obj);
            }
            else if (obj is String)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_STRING);
                writeMultiByteEx((String)obj);
            }
            else if (obj is WString)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_WIDESTR);
                writeWString((obj as WString).toStringEx());
            }
            else if (obj is Point)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_OBJECT);
                writeObject((Point)obj);
            }
            else if (obj is Double)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_DOUBLE);
                writeDouble((Double)obj);
            }
            else if (obj is Byte)
            {
                writeByte((byte)DataType.Value_Type.VARTYPE_BOOL);
                writeByte((byte)obj);
            }
        }

        /// <summary>
        /// 通信大小端的字节序
        /// </summary>
        private void ChangeByteTurn(byte[] byteArr)
        {
            if (Is_Little_Endian)
            {
                 Array.Reverse(byteArr);
            }
        }

        public void writeByte(byte obj) 
        {
            ByteArray[_length] = (Byte)obj;
            //_position += sizeof(Byte);
            _length += sizeof(Byte);
        }
        public Byte readByte()
        {
            Byte sb = ByteArray[_position];
            _position += sizeof(Byte);
            return sb;
        }

        public void writeInt8(SByte obj)
        {
            ByteArray[_length] = (byte)(SByte)obj;
            //_position += sizeof(SByte);
            _length += sizeof(SByte);
        }
        public SByte readInt8()
        {
            SByte sb = (SByte)ByteArray[_position];
            _position += sizeof(SByte);
            return sb;
        }


        public void writeInt(Int32 obj) 
        {
            byte[] temp = BitConverter.GetBytes((Int32)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(Int32));
            //_position += sizeof(Int32);
            _length += sizeof(Int32);
        }
        public Int32 readInt()
        {
            byte[] buffer = new byte[4];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 4);
            ChangeByteTurn(buffer);
            Int32 s = BitConverter.ToInt32(buffer, 0);
            _position += 4;
            return s;
        }

        public void writeUInt32(UInt32 obj)
        {
            byte[] temp = BitConverter.GetBytes((UInt32)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(UInt32));
            //_position += sizeof(UInt32);
            _length += sizeof(UInt32);
        }
        public UInt32 readUInt32()
        {
            byte[] buffer = new byte[4];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 4);
            ChangeByteTurn(buffer);
            UInt32 s = BitConverter.ToUInt32(buffer, 0);
            _position += 4;
            return s;
        }


        public void writeSignedShort(Int16 obj)
        {
            byte[] temp;
            temp = BitConverter.GetBytes((Int16)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(Int16));
            //_position += sizeof(Int16);
            _length += sizeof(Int16);
        }
        public Int16 readSignedShort()
        {
            byte[] buffer = new byte[2];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 2);
            ChangeByteTurn(buffer);
            Int16 s = BitConverter.ToInt16(buffer, 0);
            _position += 2;
            return s;
        }

        public void writeUnsignedShort(UInt16 obj)
        {
            byte[] temp;
            temp = BitConverter.GetBytes((UInt16)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(UInt16));
            //_position += sizeof(UInt16);
            _length += sizeof(UInt16);
        }
        public UInt16 readUnsignedShort()
        {
            byte[] buffer = new byte[2];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 2);
            ChangeByteTurn(buffer);
            UInt16 s = BitConverter.ToUInt16(buffer, 0);
            _position += 2;
            return s;
        }

        public void writeFloat(Single obj)
        {
            byte[]  temp = BitConverter.GetBytes((Single)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(Single));
            //_position += sizeof(Single);
            _length += sizeof(Single);
        }
        public Single readFloat()
        {
            byte[] buffer = new byte[4];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 4);
            ChangeByteTurn(buffer);
            Single s = BitConverter.ToSingle(buffer, 0);
            _position += 4;
            return s;
        }

        public void writeDouble(Double obj)
        {
            byte[] temp = BitConverter.GetBytes((Double)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(Double));
            //_position += sizeof(Double);
            _length += sizeof(Double);
        }

        public Double readDouble()
        {
            byte[] buffer = new byte[8];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 8);
            ChangeByteTurn(buffer);
            Double s = BitConverter.ToDouble(buffer, 0);
            _position += 8;
            return s;
        }

        public void writeBytes(byte[] sou) 
        {
            writeBytes(sou, 0, sou.Length);
        }
        public void writeBytes(byte[] sou, int start, int length)
        {
            if (sou == null)
            {
                return;
            }

//            ChangeByteTurn(sou);

            if (start < 0 || start > sou.Length) 
            {
                start = 0;
            }

            if (length > sou.Length)
            {
                length = sou.Length;
            }

            for (int a = 0; a < length; ++a)
            {
                ByteArray[_length + a] = sou[start + a];
            }
            //_position += length;
            _length += length;
        }

        /// <summary>
        /// 向字节数组中写入一个字符串,默认UTF-8
        /// </summary>
        /// <param name="str"></param>
        //public void writeStringEx(string str)
        //{
        //    byte[] tmp = ByteArrayTool.StringToBytes(str);
        //    this.writeBytes(tmp);
        //    //_position += tmp.Length;
        //    //_length   += tmp.Length;

        //}

        public void writeInt64(Int64 obj)
        {
            byte[] temp = BitConverter.GetBytes((Int64)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(Int64));
            //_position += sizeof(Int64);
            _length += sizeof(Int64);
        }

        public Int64 readInt64()
        {
            byte[] buffer = new byte[8];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 8);
            ChangeByteTurn(buffer);
            Int64 s = BitConverter.ToInt64(buffer, 0);
            _position += 8;
            return s;
        }

        public void writeUInt64(UInt64 obj)
        {
            byte[] temp = BitConverter.GetBytes((UInt64)obj);
            ChangeByteTurn(temp);
            Array.Copy(temp, 0, ByteArray, _length, sizeof(UInt64));
            //_position += sizeof(Double);
            _length += sizeof(UInt64);
        }

        public UInt64 readUInt64()
        {
            byte[] buffer = new byte[8];
            ByteArrayTool.BytesCopy(buffer, ByteArray, 0, _position, 8);
            ChangeByteTurn(buffer);
            UInt64 s = BitConverter.ToUInt64(buffer, 0);
            _position += 8;
            return s;
        }


        public Point readObject()
        {
            UInt64 x = readUInt64();
            Point p = new Point();
            p.z = x;
            return p;
        }

        public void writeObject(Point obj)
        {
            writeUInt64(obj.z);
        }


        /// <summary>
        /// 使用指定的字符集从字节流中读取多字节字符串,默认UTF-8//GB2312
        /// </summary>
        /// <returns></returns>
        public string readMultiByteEx()
        {
            string retStr = "";
            string singleChar = "";
            //if (bhavelenth) //是否存有长度信息
            //{
            //    int length = readShort();
            //}
            int length = readInt();
            int index = 0;
            while (bytesAvailable > 0)
            {
                if(index>=length) break;
                singleChar = readMultiByte(1);
                if (singleChar == "")
                {
                    break;
                }
                retStr += singleChar;
                index++;
            }
            return retStr;
        }
        private string readMultiByte(int length)
        {
            byte[] tmp = new byte[length];
            ByteArrayTool.BytesCopy(tmp, ByteArray, 0, _position, length);
            //ChangeByteTurn(tmp);
            string str = ByteArrayTool.BytesToString(tmp, "UTF-8");//gb2312;UTF-8//
            _position += length;
            return str;
        }

        /// <summary>
        /// 写入服务器(字符串)
        /// </summary>
		public void writeMultiByteEx(string str)
		{
            ByteArrayEx tmp = new ByteArrayEx();
            //tmp.writeInt(getStringByteLength(str));
			tmp.writeMultiByte(str);
            ByteArrayEx bytArr = new ByteArrayEx();
            bytArr.writeInt(tmp.length);//getStringByteLength(str)//
            bytArr.writeBytes(tmp.byteArray);
			//补零
//			tmp.writeByte(0);
            this.writeBytes(bytArr.byteArray);
		}
        private void writeMultiByte(string str)
        {
            byte[] tmp;
            tmp = ByteArrayTool.StringToBytes(str, "UTF-8");//gb2312;UTF-8//
            //ChangeByteTurn(tmp);
            writeBytes(tmp);
        }

        /// <summary>
        /// 获取字符串字节长度(字母长度为1，汉字长度为2)
        /// </summary>
		private int getStringByteLength(string str)
		{
            //byte[] bt = ByteArrayTool.StringToBytes(strp_str);
            //return bt.Length;
            if (str.Length == 0) return 0;
            ASCIIEncoding ascii = new ASCIIEncoding();
            int tempLen = 0; 
			byte[] s = ascii.GetBytes(str);
            for (int i = 0; i < s.Length; i++)
            {
                if ((int)s[i] == 63)
                {
                    tempLen += 2;
                }
                else
                {
                    tempLen += 1;
                }
            }
            return tempLen; 
		}

        /// <summary>
        /// 写入服务器引擎类型VISTYPE_WIDESTR(宽字符串)汉字转UTF-16
        /// </summary>
		public void writeWString(string srcStr)
		{
            ByteArrayEx assem = new ByteArrayEx();
            //assem.writeInt(srcStr.Length * 2);
            byte[] unicode = Encoding.BigEndianUnicode.GetBytes(srcStr);
            assem.writeInt(unicode.Length);
            assem.writeBytes(unicode);

            //assem.writeByte(0);
            //assem.writeByte(0);
            this.writeBytes(assem.byteArray);
		}

        /**
		 * 获取服务器引擎类型VISTYPE_WIDESTR(宽字符串)
		 * @param charSet
		 * @return 
		 * 
		 */		
		public string readWString()
		{
			string retStr = "";
			string singleChar = "";
			int length = readInt();
			while (bytesAvailable > 0 )
			{
				ByteArrayEx byteArr = new ByteArrayEx();
                byte byte1 = readByte();
                byte byte2 = readByte();
                byteArr.writeByte(byte1);
                byteArr.writeByte(byte2);
				byteArr.position = 0;
                singleChar = Encoding.BigEndianUnicode.GetString(byteArr.byteArray);
				if (singleChar == "")
				{
					break;
				}
                retStr += singleChar;
			}
			return retStr;
		}




    }
